package com.grgbanking.voice.activity;

import android.content.Context;
import android.content.SharedPreferences;
import android.databinding.DataBindingUtil;
import android.graphics.Color;
import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.os.Environment;
import android.view.MotionEvent;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.grgbanking.voice.R;
import com.grgbanking.voice.databinding.ActivityMainBinding;
import com.grgbanking.voice.exception.ServiceException;
import com.grgbanking.voice.util.BASE64Utils;
import com.grgbanking.voice.util.LogUtils;
import com.grgbanking.voice.util.OkHttpUtils;
import com.jakewharton.rxbinding.view.RxView;
import com.trello.rxlifecycle.ActivityEvent;

import org.apache.commons.lang3.StringUtils;

import java.io.BufferedOutputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.concurrent.TimeUnit;

import rx.Observable;
import rx.Subscriber;
import rx.android.schedulers.AndroidSchedulers;
import rx.functions.Action0;
import rx.functions.Action1;
import rx.functions.Func1;
import rx.schedulers.Schedulers;

public class MainActivity extends BaseActivity {

    private static final String TAG = "MainActivity";
    private static final String SERVER_URL_DATA = "server_url_data";
    private static final String SENCE = "5";
    private static final String SERVER_URL = "http://10.1.143.59:8080/grgbanking/biometrics/api";
    private static final String VOICE_FILE_PATH = Environment.getExternalStorageDirectory().getPath() + "/grgboc";
    private static final int FREQUENCE = 16000; //录制频率，单位hz
    private static final int CHANNEL_CONFIG = AudioFormat.CHANNEL_CONFIGURATION_MONO;
    private static final int AUDIO_ENCODING = AudioFormat.ENCODING_PCM_16BIT;
    private boolean isRecording = true;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ActivityMainBinding binding = DataBindingUtil.setContentView(this,
                R.layout.activity_main);
        final EditText urlEditText = binding.urlEditText;
        final EditText senceEditText = binding.senceEditText;
        final TextView resultTextView = binding.resultTextView;
        final Button saveButton = binding.saveButton;
        final Button startButton = binding.startButton;

        urlEditText.setText(SERVER_URL);
        senceEditText.setText(SENCE);
        startButton.setBackgroundColor(Color.parseColor("#99E5FE"));

        Observable.just(SERVER_URL_DATA)
                .map(new Func1<String, String[]>() {
                    @Override
                    public String[] call(String key) {
                        SharedPreferences preferences = getSharedPreferences(key,
                                Context.MODE_PRIVATE);
                        String serverUrl = null, sence = null;
                        if (preferences != null) {
                            serverUrl = preferences.getString("SERVER_URL", null);
                            if (StringUtils.isBlank(serverUrl)) {
                                serverUrl = SERVER_URL;
                            }
                            sence = preferences.getString("SENCE", null);
                            if (StringUtils.isBlank(sence)) {
                                sence = SENCE;
                            }
                        }
                        return new String[]{serverUrl, sence};
                    }
                })
                .compose(MainActivity.super.<String[]>bindUntilEvent(ActivityEvent.PAUSE))
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread()) //让subscriber运行在主线程中;
                .subscribe(new Action1<String[]>() {
                    @Override
                    public void call(String result[]) {
                        urlEditText.setText(result[0]);
                        senceEditText.setText(result[1]);
                    }
                });

        RxView.clicks(saveButton)
                .throttleFirst(1, TimeUnit.SECONDS)
                .subscribe(new Action1<Void>() {
                    @Override
                    public void call(Void aVoid) {
                        Observable.just(SERVER_URL_DATA)
                                .doOnNext(new Action1<String>() {
                                    @Override
                                    public void call(String key) {
                                        SharedPreferences preferences = getSharedPreferences(key,
                                                Context.MODE_PRIVATE);
                                        preferences.edit()
                                                .putString("SERVER_URL", urlEditText.getText().toString())
                                                .putString("SENCE", senceEditText.getText().toString())
                                                .commit();
                                    }
                                })
                                .compose(MainActivity.super.<String>bindUntilEvent(ActivityEvent.PAUSE))
                                .subscribeOn(Schedulers.io())
                                .observeOn(AndroidSchedulers.mainThread()) //让subscriber运行在主线程中;
                                .subscribe(new Action1<String>() {
                                    @Override
                                    public void call(String result) {
                                        Toast.makeText(MainActivity.this, "保存成功",
                                                Toast.LENGTH_SHORT).show();
                                    }
                                });
                    }
                });

        RxView.touches(startButton, new Func1<MotionEvent, Boolean>() {
            @Override
            public Boolean call(MotionEvent motionEvent) {
                return true;
            }
        }).subscribe(new Action1<MotionEvent>() {
            @Override
            public void call(MotionEvent motionEvent) {
                LogUtils.i(TAG, "ACTION=" + motionEvent.getAction());
                switch (motionEvent.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        LogUtils.i(TAG, "MotionEvent.ACTION_DOWN");
                        isRecording = true;
                        startButton.setBackgroundColor(Color.parseColor("#F5F5DC"));
                        resultTextView.setText("");

                        Observable.create(recording())
                                /*.subscribeOn(Schedulers.io()) //指定被观察者运行在IO线程
                                .observeOn(AndroidSchedulers.mainThread())
                                .doOnSubscribe(new Action0() {
                                    @Override
                                    public void call() {
                                        LogUtils.i(TAG, "doOnSubscribe start");
                                        Toast.makeText(MainActivity.this, "开始录音",
                                                Toast.LENGTH_SHORT).show();
                                    }
                                })*/
                                .filter(new Func1<File, Boolean>() {
                                    @Override
                                    public Boolean call(File file) {
                                        return file != null;
                                    }
                                })
                                .map(new Func1<File, String>() {
                                    @Override
                                    public String call(File file) {
                                        String result = null;
                                        try {
                                            result = BASE64Utils.encode(file);
                                        } catch (IOException e) {
                                            LogUtils.e(TAG, "编码出错", e);
                                        }
                                        return result;
                                    }
                                })
                                .filter(new Func1<String, Boolean>() {
                                    @Override
                                    public Boolean call(String result) {
                                        return StringUtils.isNotBlank(result);
                                    }
                                })
                                //.observeOn(Schedulers.io())
                                .map(new Func1<String, String>() {
                                    @Override
                                    public String call(String base64) {
                                        LogUtils.i(TAG, "===base64===");
                                        JSONObject jsonInfo = new JSONObject();
                                        jsonInfo.put("sence", senceEditText.getText().toString());
                                        jsonInfo.put("base64", base64);

                                        String resp = null;
                                        try {
                                            resp = OkHttpUtils.post(urlEditText.getText().toString(),
                                                    jsonInfo.toJSONString());
                                        } catch (IOException e) {
                                            LogUtils.e(TAG, e.getMessage(), e);
                                            throw new ServiceException(e.getMessage(), e);
                                        }
                                        return resp;
                                    }
                                })
                                .filter(new Func1<String, Boolean>() {
                                    @Override
                                    public Boolean call(String resp) {
                                        return StringUtils.isNotBlank(resp);
                                    }
                                })
                                //解决RxJava引起的内存泄漏
                                .compose(MainActivity.super.<String>bindUntilEvent(ActivityEvent.PAUSE))
                                .subscribeOn(Schedulers.io()) //指定被观察者运行在IO线程
                                .observeOn(AndroidSchedulers.mainThread()) //让subscriber运行在主线程中
                                .doOnSubscribe(new Action0() {
                                    @Override
                                    public void call() {
                                        LogUtils.i(TAG, "doOnSubscribe start");
                                        Toast.makeText(MainActivity.this, "开始录音",
                                                Toast.LENGTH_SHORT).show();
                                    }
                                })
                                .subscribe(new Action1<String>() {
                                    @Override
                                    public void call(String resp) {
                                        LogUtils.i(TAG, "resp=" + resp);
                                        JSONObject json = JSON.parseObject(resp, JSONObject.class);
                                        if (json.containsKey("message")) {
                                            resultTextView.setText(json.getString("message"));
                                        }
                                    }
                                }, new Action1<Throwable>() {
                                    @Override
                                    public void call(Throwable throwable) {
                                        LogUtils.i(TAG, "onError");
                                        if (throwable instanceof ServiceException) {
                                            Toast.makeText(MainActivity.this, "URL地址异常",
                                                    Toast.LENGTH_SHORT).show();
                                        }
                                    }
                                }, new Action0() {
                                    @Override
                                    public void call() {
                                        LogUtils.i(TAG, "onCompleted");
                                    }
                                });
                        break;
                    case MotionEvent.ACTION_UP:
                        LogUtils.i(TAG, "MotionEvent.ACTION_UP");
                        isRecording = false;
                        startButton.setBackgroundColor(Color.parseColor("#99E5FE"));
                        break;
                }
            }
        });
    }

    private File createTempFile() {
        //在这里我们创建一个文件，用于保存录制内容
        File fpath = new File(VOICE_FILE_PATH);
        if (!fpath.exists()) {
            fpath.mkdirs();//创建文件夹
        }
        LogUtils.i(TAG, "fpath=" + fpath.getPath());
        //创建临时文件,注意这里的格式为.pcm
        return new File(VOICE_FILE_PATH, "recording.pcm");
    }

    /**
     * 将short转成byte数组，低字节在前
     *
     * @param n
     * @return
     */
    private byte[] shortToBytes(short n) {
        byte[] b = new byte[2];
        b[0] = (byte) (n & 0xff);
        b[1] = (byte) ((n >> 8) & 0xff);
        return b;
    }

    private Observable.OnSubscribe<File> recording() {
        //被观察者
        return new Observable.OnSubscribe<File>() {
            @Override
            public void call(Subscriber<? super File> subscriber) {
                LogUtils.i(TAG, "OnSubscribe start");
                File voiceFile = createTempFile();
                if (voiceFile != null) {
                    AudioRecord record = null;
                    DataOutputStream dos = null;
                    try {
                        //开通输出流到指定的文件
                        dos = new DataOutputStream(new BufferedOutputStream(
                                new FileOutputStream(voiceFile)));
                        //根据定义好的几个配置，来获取合适的缓冲大小
                        int bufferSize = AudioRecord.getMinBufferSize(FREQUENCE, CHANNEL_CONFIG,
                                AUDIO_ENCODING);
                        //实例化AudioRecord
                        record = new AudioRecord(MediaRecorder.AudioSource.MIC, FREQUENCE,
                                CHANNEL_CONFIG, AUDIO_ENCODING, bufferSize);
                        //定义缓冲
                        short[] buffer = new short[bufferSize];

                        //开始录制
                        record.startRecording();
                        //定义循环，根据isRecording的值来判断是否继续录制
                        while (isRecording) {
                            //从bufferSize中读取字节，返回读取的short个数
                            int bufferReadResult = record.read(buffer, 0, buffer.length);
                            //循环将buffer中的音频数据写入到OutputStream中
                            for (int i = 0; i < bufferReadResult; i++) {
                                dos.write(shortToBytes(buffer[i]));
                            }
                        }
                    } catch (IOException e) {
                        voiceFile = null;
                        LogUtils.e(TAG, "录音出错", e);
                    } finally {
                        if (record != null) {
                            record.stop();
                            record.release();
                        }
                        if (dos != null) {
                            try {
                                dos.close();
                            } catch (IOException e) {
                            }
                        }
                        isRecording = false;
                    }
                }
                subscriber.onNext(voiceFile);
                subscriber.onCompleted();
            }
        };
    }
}
